package cn.iocoder.yudao.module.resource.service.usertimebalance;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.infra.api.config.IConfigApi;
import cn.iocoder.yudao.module.resource.api.enums.EnumAipError;
import cn.iocoder.yudao.module.resource.api.enums.UserTimeTransactionTypeEnum;
import cn.iocoder.yudao.module.resource.controller.admin.usertimebalance.vo.UserTimeBalancePageReqVO;
import cn.iocoder.yudao.module.resource.controller.admin.usertimebalance.vo.UserTimeBalanceSaveReqVO;
import cn.iocoder.yudao.module.resource.dal.dataobject.usertimebalance.UserTimeBalanceDO;
import cn.iocoder.yudao.module.resource.dal.dataobject.usertimetransaction.UserTimeTransactionDO;
import cn.iocoder.yudao.module.resource.dal.mysql.usertimebalance.UserTimeBalanceMapper;
import cn.iocoder.yudao.module.resource.dal.redis.ResourceLockRedisDAO;
import cn.iocoder.yudao.module.resource.service.usertimemanager.IUserTimeManagerService;
import cn.iocoder.yudao.module.resource.service.usertimetransaction.UserTimeTransactionService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 用户时长余额 Service 实现类
 *
 * @author lizhongwen
 */
@Slf4j
@Service
@Validated
public class UserTimeBalanceServiceImpl implements UserTimeBalanceService {
    private static final String KEY_USER_TIME_NEW_USER_GIVE = "user_time_new_user_give";

    @Resource
    private UserTimeBalanceMapper userTimeBalanceMapper;
    @Resource
    private UserTimeTransactionService userTimeTransactionService;
    @Resource
    private IUserTimeManagerService userTimeManagerService;
    @Resource
    private ResourceLockRedisDAO resourceLockRedisDAO;
    @Resource
    private IConfigApi configApi;

    @Override
    public String createUserTimeBalance(UserTimeBalanceSaveReqVO createReqVO) {
        // 插入
        UserTimeBalanceDO userTimeBalance = BeanUtils.toBean(createReqVO, UserTimeBalanceDO.class);
        userTimeBalanceMapper.insert(userTimeBalance);
        // 返回
        return userTimeBalance.getId();
    }

    @Override
    public void updateUserTimeBalance(UserTimeBalanceSaveReqVO updateReqVO) {
        // 校验存在
        validateUserTimeBalanceExists(updateReqVO.getId());
        // 更新
        UserTimeBalanceDO updateObj = BeanUtils.toBean(updateReqVO, UserTimeBalanceDO.class);
        userTimeBalanceMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserTimeBalance(String id) {
        // 校验存在
        validateUserTimeBalanceExists(id);
        // 删除
        userTimeBalanceMapper.deleteById(id);
    }

    private void validateUserTimeBalanceExists(String id) {
        if (userTimeBalanceMapper.selectById(id) == null) {
            throw exception(EnumAipError.USER_TIME_BALANCE_NOT_EXISTS);
        }
    }

    @Override
    public UserTimeBalanceDO getUserTimeBalance(String id) {
        return userTimeBalanceMapper.selectById(id);
    }

    @Override
    public PageResult<UserTimeBalanceDO> getUserTimeBalancePage(UserTimeBalancePageReqVO pageReqVO) {
        return userTimeBalanceMapper.selectPage(pageReqVO);
    }

    @Override
    public UserTimeBalanceDO getUserTimeBalanceByUserId(Long userId) {
        return userTimeBalanceMapper.selectOne(UserTimeBalanceDO::getUserId, userId);
    }

    @Override
    public UserTimeBalanceDO getUserTimeBalanceByUserIdWithNewUserGive(Long userId) {
        return resourceLockRedisDAO.lockUserBalance(userId, () -> {
            final Boolean existed = userTimeTransactionService.hasUserTimeTransactionByType(userId, UserTimeTransactionTypeEnum.NEW_USER_GIVE);
            if (!existed) {
                final String minute = configApi.getValueByKey(KEY_USER_TIME_NEW_USER_GIVE);
                final Long timeMs = StrUtil.isNotEmpty(minute) ? Long.parseLong(minute) * 60 * 1000 : 0L;

                if (timeMs > 0) {
                    log.info("新用户赠送时长, userId = {}, minute = {}, timeMs = {}", userId, minute, timeMs);
                    userTimeManagerService.purchaseTime(userId, UserTimeTransactionTypeEnum.NEW_USER_GIVE, null, timeMs);
                } else {
                    log.error("新用户赠送时长-时长不合法, userId = {}, minute = {}, timeMs = {}", userId, minute, timeMs);
                }
            }

            return getUserTimeBalanceByUserId(userId);
        });
    }
}